using System;
using System.Collections.Generic;
using System.DirectoryServices.ActiveDirectory;
using System.Xml.Serialization;

namespace ActiveDirectoryUtilities.ReplDiag
{
	public class DomainControllerReplicationInfo
	{
		private string _dcName, _siteName, _ntdsDsaObjectName;
		private Guid _ntDsaGuid = Guid.Empty;
		private List<NamingContextInfo> _hostedNCs = new List<NamingContextInfo>();
		private int _errorCode;
		private string _errorMessage = string.Empty;
		private string _stack = string.Empty;
		private TimeSpan _totalDataCollection, _ncDataCollectionOnlyDuration;

		public string DCName
		{
			get { return _dcName; }
			set { _dcName = value.ToLower(); }
		}

		public string SiteName
		{
			get { return _siteName; }
			set { _siteName = value.ToLower(); }
		}

		public Guid NtDsaGuid
		{
			get { return _ntDsaGuid; }
			set { _ntDsaGuid = value; }
		}

		public string NtdsDsaObjectName
		{
			get { return _ntdsDsaObjectName; }
			set { _ntdsDsaObjectName = value; }
		}

		public List<NamingContextInfo> HostedNcs
		{
			get { return _hostedNCs; }
			set { _hostedNCs = value; }
		}

		public int ErrorCode
		{
			get { return _errorCode; }
			set { _errorCode = value; }
		}

		public string ErrorMessage
		{
			get { return _errorMessage.Replace("\n", " ").Replace("\r", "").Trim(); }
			set { _errorMessage = value; }
		}

		public string StackTrace
		{
			get { return _stack; }
			set { _stack = value; }
		}

		[XmlIgnore]
		public TimeSpan DataCollectionDuration { get { return _totalDataCollection; } }

		[XmlIgnore]
		public TimeSpan ReplicationStateDataCollectionDuration { get { return _ncDataCollectionOnlyDuration; } }

		public long totalCollectionTicks
		{
			get { return _totalDataCollection.Ticks; }
			set { _totalDataCollection = new TimeSpan(value); }
		}

		public long replicationCollectionTicks
		{
			get { return _ncDataCollectionOnlyDuration.Ticks; }
			set { _ncDataCollectionOnlyDuration = new TimeSpan(value); }
		}

		private DomainControllerReplicationInfo()
		{
		}

		public DomainControllerReplicationInfo(string dcName)
		{
			_dcName = dcName.ToLower();
		}

		public void AddNC(string ncName, bool isWritable)
		{
			_hostedNCs.Add(new NamingContextInfo(ncName.ToLower(), isWritable));
		}

		public void AddReplicationNeighbor(string ncName, string sourceServer, DateTime lastSuccessfulSync, int failureCount, int lastSyncResultCode, string lastSyncResultMessage)
		{
			//assumes the NC has already been added to the server.  If not we need to troubleshoot the bug for why the NC does not already exist on this server.
			this[ncName.ToLower()].ReplicationConnections.Add(new ReplicationInfo(sourceServer, lastSuccessfulSync, failureCount, lastSyncResultCode, lastSyncResultMessage));
		}

		public void AddDataCollectionTimes(TimeSpan totalDataCollection, TimeSpan ncDataCollectionOnlyDuration)
		{
			_totalDataCollection = totalDataCollection;
			_ncDataCollectionOnlyDuration = ncDataCollectionOnlyDuration;
		}

		public NamingContextInfo this[string ncName]
		{
			get
			{
				foreach (NamingContextInfo nci in _hostedNCs)
				{
					if (string.Compare(nci.NCName, ncName.ToLower(), true) == 0)
					{
						return nci;
					}
				}
				return null;
				//throw new ApplicationException("Error processing replication connections on " + _dcName + ".  There is a replication connection for an NC that should not exist on the DC.");
			}
		}

		public bool Contains(string namingContext)
		{
			foreach (NamingContextInfo nci in _hostedNCs)
			{
				if (string.Compare(nci.NCName, namingContext, true) == 0)
				{
					return true;
				}
			}
			return false;
		}
	}

	public class NamingContextInfo
	{
		private string _ncName;
		private bool _isWritable;
		private List<ReplicationInfo> _replConn = new List<ReplicationInfo>();

		public string NCName
		{
			get { return _ncName; }
			set { _ncName = value.ToLower(); }
		}

		public bool IsWritable
		{
			get { return _isWritable; }
			set { _isWritable = value; }
		}

		public List<ReplicationInfo> ReplicationConnections
		{
			get { return _replConn; }
			set { _replConn = value; }
		}

		private NamingContextInfo()
		{
		}

		public NamingContextInfo(string ncName, bool isWritable)
		{
			_ncName = ncName.ToLower();
			_isWritable = isWritable;
		}

		public ReplicationInfo GetReplicationStateToServer(string serverName)
		{
			foreach (ReplicationInfo ri in _replConn)
			{
				if (string.Compare(serverName, ri.SourceServer, true) == 0)
				{
					return ri;
				}
			}

			return null;
		}
	}

	public class ReplicationInfo
	{
		private string _sourceServer;
		private DateTime _lastSuccessfulSync;
		private int _consecutiveFailureCount, _lastSyncResult;
		private string _lastSyncErrorMessage;

		public string SourceServer
		{
			get { return _sourceServer; }
			set { _sourceServer = value; }
		}

		public DateTime LastSuccessfulSync
		{
			get { return _lastSuccessfulSync; }
			set { _lastSuccessfulSync = value; }
		}

		public int ConsecutiveFailureCount
		{
			get { return _consecutiveFailureCount; }
			set { _consecutiveFailureCount = value; }
		}

		public int LastSyncResultCode
		{
			get { return _lastSyncResult; }
			set { _lastSyncResult = value; }
		}

		public string LastSyncResultMessage
		{
			get { return _lastSyncErrorMessage; }
			set { _lastSyncErrorMessage = value.Replace("\n", " ").Replace("\r", ""); }
		}

		private ReplicationInfo()
		{
		}

		public ReplicationInfo(string sourceServer, DateTime lastSuccessfulSync, int consecutiveFailureCount)
		{
			_sourceServer = sourceServer.ToLower();
			_lastSuccessfulSync = lastSuccessfulSync;
			_consecutiveFailureCount = consecutiveFailureCount;
		}

		public ReplicationInfo(string sourceServer, DateTime lastSuccessfulSync, int consecutiveFailureCount, int lastSyncResultCode, string lastSyncResultMessage)
		{
			_sourceServer = sourceServer.ToLower();
			_lastSuccessfulSync = lastSuccessfulSync;
			_consecutiveFailureCount = consecutiveFailureCount;
			_lastSyncResult = lastSyncResultCode;
			_lastSyncErrorMessage = lastSyncResultMessage;
		}
	}
}
